﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WeDonekRpc.CacheClient.Config;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.CacheClient.Redis;
using WeDonekRpc.Helper;
using StackExchange.Redis;

namespace WeDonekRpc.CacheClient.Batch
{
    internal class RedisBatchWrite : IRedisBatchWrite
    {
        private readonly IBatch _Batch;
        public RedisBatchWrite (IBatch Batch)
        {
            this._Batch = Batch;
        }
        private readonly List<Task> _BatchTask = new List<Task>();

        public void Add<T> (string key, string colname, T data)
        {
            this._BatchTask.Add(this._Batch.HashSetAsync(key, colname, RedisTools.Serializable<T>(data), When.NotExists));
        }

        public void Add<T> (string key, T data, TimeSpan? expires = null)
        {
            expires = CacheTimeConfig.FormatCacheTime(key, expires);
            this._BatchTask.Add(this._Batch.StringSetAsync(key, RedisTools.Serializable<T>(data), expires, When.NotExists, CommandFlags.None));
        }


        public void ListTop (string key, int start, int end)
        {
            this._BatchTask.Add(this._Batch.ListTrimAsync(key, start, end));
        }

        public void Decrement (string key, double num)
        {
            this._BatchTask.Add(this._Batch.StringDecrementAsync(key, num));
        }

        public void Decrement (string key, long num)
        {
            this._BatchTask.Add(this._Batch.StringDecrementAsync(key, num));
        }

        public void Decrement (string key, string colname, double num)
        {
            this._BatchTask.Add(this._Batch.HashDecrementAsync(key, colname, num));
        }

        public void Decrement (string key, string colname, long num)
        {
            this._BatchTask.Add(this._Batch.HashDecrementAsync(key, colname, num));
        }


        public void Increment (string key, double num)
        {
            this._BatchTask.Add(this._Batch.StringIncrementAsync(key, num));
        }

        public void Increment (string key, long num)
        {
            this._BatchTask.Add(this._Batch.StringIncrementAsync(key, num));
        }

        public void Increment (string key, string colname, double num)
        {
            this._BatchTask.Add(this._Batch.HashIncrementAsync(key, colname, num));
        }

        public void Increment (string key, string colname, long num)
        {
            this._BatchTask.Add(this._Batch.HashIncrementAsync(key, colname, num));
        }

        public void ListAppend<T> (string key, T[] data)
        {
            this._BatchTask.Add(this._Batch.ListRightPushAsync(key, data.ConvertAll(a => RedisTools.Serializable<T>(a))));
        }

        public void ListAppend<T> (string key, T data)
        {
            this._BatchTask.Add(this._Batch.ListRightPushAsync(key, RedisTools.Serializable<T>(data)));
        }

        public void ListInsert<T> (string key, T[] data)
        {
            this._BatchTask.Add(this._Batch.ListLeftPushAsync(key, data.ConvertAll(a => RedisTools.Serializable<T>(a))));
        }

        public void ListInsert<T> (string key, T data)
        {
            this._BatchTask.Add(this._Batch.ListLeftPushAsync(key, RedisTools.Serializable<T>(data)));
        }

        public void ListRemove<T> (string key, T data)
        {
            this._BatchTask.Add(this._Batch.ListRemoveAsync(key, RedisTools.Serializable<T>(data)));
        }

        public void Remove (string key, string colname)
        {
            this._BatchTask.Add(this._Batch.HashDeleteAsync(key, colname));
        }

        public void Remove (string[] key)
        {
            this._BatchTask.Add(this._Batch.KeyDeleteAsync(key.Cast<RedisKey>().ToArray()));
        }

        public void Remove (string key, string[] colname)
        {
            this._BatchTask.Add(this._Batch.HashDeleteAsync(key, colname.Cast<RedisValue>().ToArray()));
        }

        public void Remove (string key)
        {
            this._BatchTask.Add(this._Batch.KeyDeleteAsync(key));
        }

        public void Replace<T> (string key, string colname, T data)
        {
            this._BatchTask.Add(this._Batch.HashSetAsync(key, colname, RedisTools.Serializable<T>(data), When.Exists));
        }

        public void Replace<T> (string key, T data, TimeSpan? expires = null)
        {
            expires = CacheTimeConfig.FormatCacheTime(key, expires);
            this._BatchTask.Add(this._Batch.StringSetAsync(key, RedisTools.Serializable<T>(data), expires, When.Exists, CommandFlags.None));
        }

        public void Set<T> (string key, string colname, T data)
        {
            this._BatchTask.Add(this._Batch.HashSetAsync(key, colname, RedisTools.Serializable<T>(data)));
        }

        public void Set<T> (string key, T data, DateTime expires)
        {
            this._BatchTask.Add(this._Batch.StringSetAsync(key, RedisTools.Serializable<T>(data), expires - DateTime.Now));
        }

        public void Set<T> (string key, T data, TimeSpan? expires = null)
        {
            expires = CacheTimeConfig.FormatCacheTime(key, expires);
            this._BatchTask.Add(this._Batch.StringSetAsync(key, RedisTools.Serializable<T>(data), expires));
        }

        public void SetExpire (string key, DateTime time)
        {
            this._BatchTask.Add(this._Batch.KeyExpireAsync(key, time));
        }

        public object[] Submit ()
        {
            if (this._BatchTask.Count > 0)
            {
                this._Batch.Execute();
                return this._BatchTask.ConvertAllToArray(a => a.GetObjectValue("Result"));
            }
            return new object[0];
        }

    }
}
